import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.preprocessing import MinMaxScaler
from iotdb.dbapi import connect
import re
import os
import pymysql
import matplotlib
matplotlib.use('TkAgg')

import templates

# 项目活跃度预测存入mysql

com_json=templates.DATA_JSON()
db_iotdb=templates.DB_IOTDB()
db_mysql=templates.DB_MYSQL()


def createXY(dataset, step):
    dataX, dataY = [], []
    for i in range(len(dataset) - step):
        a = dataset[i:(i + step), 0]
        dataX.append(a)
        dataY.append(dataset[i + step, 0])
    return np.array(dataX), np.array(dataY)


class OPEN_IOTDB:
    def activity_tend(self,item_name):
        db_iotdb.iotdb()
        self.cursor = db_iotdb.conn.cursor()

        sql = f"select activity from root.opendigger.{item_name} ORDER BY TIME"
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
        second_elements = [item[1] for item in result]
        df = pd.DataFrame(second_elements, columns=['Value'])
        return df

class OPEN_MYSQL:
    def act_predict(self,item_name,future_data):
        db_mysql.Connect()
        self.cursor = db_mysql.con.cursor()
        try:
            sql = '''INSERT IGNORE INTO lstm_predicts (item,future_data) VALUES ("{0}", "{1}")'''.format(item_name,future_data)
            self.cursor.execute(sql)
            db_mysql.con.commit()

        except Exception as e:
            print(e)
        finally:
            self.cursor.close()
            db_mysql.con.close()


def lstm(item_name):
    model = OPEN_IOTDB()
    df = model.activity_tend(f'{item_name}')
    # 读取数据
    dataset = np.array(df['Value']).reshape(-1, 1)  # 直接使用 reshape 而不是两步操作
    # 划分训练集、测试集
    train_size = int(len(dataset) * 0.8)
    dataset_train, dataset_test = dataset[:train_size], dataset[train_size:]
    # print(dataset_test)
    # 标准化数据
    scaler = MinMaxScaler(feature_range=(0, 1))
    dataset_train_scaled = scaler.fit_transform(dataset_train)
    dataset_test_scaled = scaler.transform(dataset_test)

    # 生成样本
    step = 1
    trainX, trainY = createXY(dataset_train_scaled, step)
    testX, testY = createXY(dataset_test_scaled, step)

    # 重塑输入数据以匹配 LSTM 的输入要求 [batch_size, time_steps, features]
    trainX_input = trainX.reshape((trainX.shape[0], step, 1))
    testX_input = testX.reshape((testX.shape[0], step, 1))

    # 构建模型
    model = tf.keras.models.Sequential([
        tf.keras.layers.LSTM(4, input_shape=(step, 1)),
        tf.keras.layers.Dense(1)  # Dense 层默认使用线性激活函数，对于回归任务这是合适的
    ])
    model.compile(loss='mean_squared_error', optimizer='adam')

    # 训练模型
    model.fit(trainX_input, trainY, batch_size=1, epochs=50, verbose=1)

    # 预测
    prediction_test = model.predict(testX_input)
    prediction_train = model.predict(trainX_input)

    # 逆变换预测结果以还原到原始尺度,在该项目画图部分没有展示，所以以下变量未用到
    prediction_train_inverse = scaler.inverse_transform(prediction_train)
    prediction_test_inverse = scaler.inverse_transform(prediction_test)
    testY_inverse = scaler.inverse_transform(testY.reshape(-1, 1))
    trainY_inverse = scaler.inverse_transform(trainY.reshape(-1, 1))


    # 预测未来几天的数据
    def predict_future(model, last_data, n_steps, scaler):
        future_predictions = []
        current_input = last_data

        for _ in range(n_steps):
            # 模型预测下一步
            next_prediction = model.predict(current_input)
            future_predictions.append(next_prediction[0, 0])

            # 将预测结果作为下一步的输入
            next_input = np.array([[next_prediction[0, 0]]])  # 重新包装为输入格式
            current_input = next_input.reshape((1, 1, 1))  # 适应LSTM的输入形状

        # 逆变换预测结果以还原到原始尺度
        future_predictions_inverse = scaler.inverse_transform(np.array(future_predictions).reshape(-1, 1))
        return future_predictions_inverse

    # 使用训练集最后的一个数据作为初始值来预测未来 10 天
    last_data = [testX_input[-1]]  # 获取训练集最后一天的数据
    # print(testX_input)
    # print(last_data)
    future_steps = 10  # 预测未来10天
    future_predictions = predict_future(model, last_data, future_steps, scaler)
    # print(future_predictions)
    future_data = future_predictions[:5]
    future_data = [round(float(item[0]), 2) for item in future_data]
    # 返回未来的预测结果
    future_data.insert(0, 'predict_data')
    ope=OPEN_MYSQL()
    ope.act_predict(item_name,future_data)


# comm=COMMON()
for i in range(100):
    table, goal=com_json.dir_json(i)
    lstm(table)
    # print(table,goal)
    # break


